package v1

import (
	"gin-wave-im/global"
	"gin-wave-im/middleware"
	"gin-wave-im/model"
	"gin-wave-im/model/request"
	"gin-wave-im/model/response"
	"gin-wave-im/service"
	"gin-wave-im/util"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis"
	"go.uber.org/zap"
	"time"
)

// @Tags Base
// @Summary 注册
// @Produce application/json
// @Param data body request.Register true "手机号, 密码"
// @Success 200 {string} string "{"code":200,"data":null,"msg":"注册成功！"}"
// @Router /v1/auth/register [post]
func Register(ctx *gin.Context) {
	register := &request.Register{}
	if err := ctx.ShouldBindJSON(register);err != nil {
		response.Fail(ctx, -1, util.Error(err))
		return
	}
	err := service.Register(*register)
	if err != nil {
		global.GnLog.Error(err.Error(), zap.Any("err", err))
		response.Fail(ctx, -1, err.Error())
	} else {
		response.Success(ctx, nil, "注册成功！")
	}
}

// @Tags Base
// @Summary 登录
// @Produce application/json
// @Param data body request.Login true "手机号, 密码"
// @Success 200 {string} string "{"code":200,"data":null,"msg":"登录成功！"}"
// @Router /v1/auth/login [post]
func Login(ctx *gin.Context) {
	login := &request.Login{}
	if err := ctx.ShouldBindJSON(login);err != nil {
		response.Fail(ctx, -1, util.Error(err))
		return
	}
	user,err := service.Login(*login)
	if err != nil {
		response.Fail(ctx, 422, "没有该用户")
		return
	}

	// 发放token
	issueToken(ctx, user)
}

// 发放token
func issueToken(ctx *gin.Context, user model.User) {
	j := &middleware.JWT{SecretKey: []byte(global.GnConfig.JWT.SecretKey)} // 唯一签名
	claims := request.LoginClaims{
		ID:          user.ID,
		NickName:    user.Nickname,
		BufferTime:  global.GnConfig.JWT.BufferTime, // 缓冲时间1天 缓冲时间内会获得新的token刷新令牌 此时一个用户会存在两个有效令牌 但是前端只留一个 另一个会丢失
		StandardClaims: jwt.StandardClaims{
			NotBefore: time.Now().Unix() - 1000,                            // 签名生效时间
			ExpiresAt: time.Now().Unix() + global.GnConfig.JWT.ExpiresTime, // 过期时间 7天  配置文件
			Issuer: "gin demo",
			Subject: "user token",
		},
	}
	token,err := j.CreateToken(claims)
	if err != nil {
		response.Fail(ctx, 500, "系统异常！")
		global.GnLog.Error("token generate error: ", zap.Any("err", err))
		return
	}
	repUser := response.TokenResponse{
		//User:      user,
		Token:     token,
		ExpiresAt: claims.StandardClaims.ExpiresAt,
	}
	if !global.GnConfig.System.UseMultipoint {
		response.Success(ctx, repUser, "登录成功！")
		return
	}
	if err, jwtStr := service.GetRedisJWT(user.ID); err == redis.Nil {
		if err := service.SetRedisJWT(token, user.ID); err != nil {
			global.GnLog.Error("设置登录状态失败", zap.Any("err", err))
			response.Fail(ctx, 422, "设置登录状态失败")
			return
		}
		response.Success(ctx, repUser, "登录成功！")
	} else if err != nil {
		global.GnLog.Error("设置登录状态失败", zap.Any("err", err))
		response.Fail(ctx, 422, "设置登录状态失败")
	} else {
		var blackJWT model.JwtBlacklist
		blackJWT.Jwt = jwtStr
		if err := service.JsonInBlacklist(blackJWT); err != nil {
			response.Fail(ctx, 422, "jwt作废失败")
			return
		}
		if err := service.SetRedisJWT(token, user.ID); err != nil {
			response.Fail(ctx, 422, "设置登录状态失败")
			return
		}
		response.Success(ctx, repUser, "登录成功！")
	}
}

// @Tags User
// @Summary 退出
// @Produce application/json
// @Param Authorization header string true "验证参数Bearer和token空格拼接"
// @Success 200 {string} string "{"code":200,"data":{},"msg":"退出成功！"}"
// @Router /v1/auth/logout [get]
func Logout(ctx *gin.Context) {
	userId := service.GetUserID(ctx)
	if err := service.DelRedisJWT(userId); err != nil {
		response.Fail(ctx, 500, "删除登录状态失败")
		return
	}
	response.Success(ctx, nil, "退出成功！")
}

// @Tags User
// @Summary 用户信息
// @Produce application/json
// @Param Authorization header string true "验证参数Bearer和token空格拼接"
// @Param userId query int true "用户id" length(20)
// @Success 200 {string} string "{"code":200,"data":{},"msg":"用户信息！"}"
// @Router /v1/user/info [get]
func Info(ctx *gin.Context) {
	info := &request.UserInfo{}
	if err := ctx.ShouldBindQuery(info);err != nil {
		response.Fail(ctx, -1, util.Error(err))
		return
	}
	userId := service.GetUserID(ctx)
	if info.UserId > 0 {
		userId = info.UserId
	}
	user,err := service.UserInfo(userId)
	if err != nil {
		response.Fail(ctx, -1, "查询失败")
	} else {
		response.Success(ctx, user, "用户信息！")
	}
}

// @Tags User
// @Summary 搜索用户
// @Produce application/json
// @Param Authorization header string true "验证参数Bearer和token空格拼接"
// @Param mobile query string true "手机号" length(11)
// @Success 200 {string} string "{"code":200,"data":{},"msg":"搜索用户成功！"}"
// @Router /auth/search [get]
func Search(ctx *gin.Context) {
	search := &request.Search{}
	if err := ctx.ShouldBindQuery(search);err != nil {
		response.Fail(ctx, -1, util.Error(err))
		return
	}
	user,_ := service.UserByMobile(search.Mobile)
	if user.ID == 0 {
		response.Fail(ctx, 422, "用户不存在！")
	} else {
		response.Success(ctx, user, "搜索用户成功！")
	}
}

// @Tags User
// @Summary 修改用户信息
// @Produce application/json
// @Param data body request.UserModify true "昵称, 性别, 简介, 头像"
// @Success 200 {string} string "{"code":200,"data":{},"msg":"修改成功！"}"
// @Router /v1/auth/modify [put]
func Modify(ctx *gin.Context) {
	userModify := &request.UserModify{}
	if err := ctx.ShouldBindJSON(userModify);err != nil {
		response.Fail(ctx, -1, util.Error(err))
		return
	}
	userId := service.GetUserID(ctx)
	err := service.Modify(*userModify, userId)
	if err != nil {
		global.GnLog.Error(err.Error(), zap.Any("err", err))
		response.Fail(ctx, -1, err.Error())
	} else {
		response.Success(ctx, nil, "修改成功！")
	}
}